package com.tencent.sr.iris.activity.service.event.activity;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tencent.sr.bizmid.user.core.interfaces.enums.UserCoreStatus;
import com.tencent.sr.iris.activity.dependency.qufa.GroupTaskDependency;
import com.tencent.sr.iris.activity.domain.event.dto.ActivityCheckResultDTO;
import com.tencent.sr.iris.activity.domain.event.dto.ActivityDTO;
import com.tencent.sr.iris.activity.domain.event.dto.ActivityTaskDTO;
import com.tencent.sr.iris.activity.domain.event.dto.SpecialOldTttResultDTO;
import com.tencent.sr.iris.activity.interfaces.event.dto.ActivityEventDTO;
import com.tencent.sr.iris.activity.interfaces.request.acticity.QuFaUserHasJoinNormalPromoteRequest;
import com.tencent.sr.iris.activity.interfaces.response.group.task.QuFaUserHasJoinNormalPromoteRes;
import com.tencent.sr.iris.activity.service.activity.ActivityCommonService;
import com.tencent.sr.iris.activity.service.activity.IrisUserTaskRecordService;
import com.tencent.sr.iris.activity.service.config.ActivityConfig;
import com.tencent.sr.iris.activity.service.config.ResponseMockConfig;
import com.tencent.sr.iris.activity.service.event.task.IrisTaskExecutor;
import com.tencent.sr.iris.activity.service.event.util.ActivityCommonUtilService;
import com.tencent.sr.iris.user.core.service.interfaces.dto.user.UserWideDTO;
import com.tencent.sr.iris.user.core.service.interfaces.enums.LeaderTypeEnum;
import com.tencent.sr.iris.user.core.service.interfaces.enums.StaffFromTypeEnum;
import com.tencent.sr.iris.user.core.service.interfaces.enums.UserLevelEnum;
import com.tencent.sr.iris.user.core.service.interfaces.response.activity.SpecialInviteResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author xiaojun
 *         注：当前活动处理器的对象名称是 活动类型ActivityEventTypeEnum的code
 */
@Slf4j
@Component
public class IrisMonthGiftActivityExecutor extends AbstractIrisActivityExecutor {

    @Resource
    private ActivityConfig activityConfig;

    @Resource
    private GroupTaskDependency groupTaskDependency;

    @Resource
    private ActivityCommonService activityCommonService;

    @Resource
    private ActivityCommonUtilService activityCommonUtilService;

    @Resource
    private IrisUserTaskRecordService userTaskRecordService;

    @Resource
    private ResponseMockConfig responseMockConfig;

    @Override
    protected void process(ActivityEventDTO msg, ActivityDTO activity, List<String> eventHandingInfoList) {
        //1.活动准入规则校验
        ActivityCheckResultDTO activityFlag = doActivityCheck(activity, msg);
        if (!activityFlag.isSatisfy()) {
            log.info("不满足活动准入规则,activityId={},errorMsg:{},msg={}", activity.getBizId(), activityFlag.getErrorMsg(),
                    JSONObject.toJSONString(msg));
            eventHandingInfoList.add("不满足活动准入规则,errorMsg=" + activityFlag.getErrorMsg());
            return;
        }

        //2.活动准入规则校验，不满足则删除进行中的任务记录
        ActivityCheckResultDTO accessConditionCheckResult = doAccessConditionCheck(activity, msg);
        if (!accessConditionCheckResult.isSatisfy()) {
            log.info("月月领不满足活动准入规则,activityId={},errorMsg:{}, msg={}", activity.getBizId(),
                    accessConditionCheckResult.getErrorMsg(),
                    JSONObject.toJSONString(msg));
            eventHandingInfoList.add("月月领不满足活动准入规则,errorMsg=" + accessConditionCheckResult.getErrorMsg());
            //如果不满足活动任务门槛，删除已存在的进行中任务记录
            int i = userTaskRecordService.deleteInProgressTaskRecord(msg.getUid(), activity.getBizId(), null);
            eventHandingInfoList.add("月月领删除进行中的任务记录,result:" + i + "条");
            activityRecordService.handleInProgressActivityRecord(msg.getUid(),activity.getBizId());
            return;
        }

        if (CollectionUtils.isEmpty(activity.getActivityTaskDTOS())) {
            log.info("当前事件对应的活动中无可执行的任务,idempotent={},eventType={},activityId={}", msg.getIdempotent(),
                    msg.getEventType(), activity.getBizId());
            eventHandingInfoList
                    .add("当前事件对应的活动中无可执行的任务,activityId=" + activity.getId() + "msgIdempotent=" + msg.getIdempotent());
            return;
        }

        activity.getActivityTaskDTOS().forEach(t -> {
            //获取任务执行器
            IrisTaskExecutor taskExecutor = getTaskExecutor(msg, activity, t);
            taskExecutor.execute(msg, activity, t, null);
        });

        activityRecordService.addOrUpdateActivityRecord(msg.getUid(), msg.getEventTime(), activity.getBizId(),
                activity.getPeriodType(), activity.getPeriod());
    }

    @Override
    protected void after(ActivityEventDTO eventDTO, ActivityDTO act) {

    }

    @Override
    protected List<ActivityTaskDTO> getTask(ActivityEventDTO eventDTO, ActivityDTO act) {
        return null;
    }


    @Override
    protected void check(ActivityEventDTO msg, ActivityDTO activity) {

    }

    @Override
    public ActivityCheckResultDTO doAccessConditionCheck(ActivityDTO activity, ActivityEventDTO msg) {
        Long changeTime = msg.getEventTime();

        String uid = msg.getUid();
        String pid = msg.getPid();
        //见习会员时间校验
        Long traineeTime = activityCommonService.queryTraineeTime(uid);
        if (traineeTime == null) {
            log.info("不是见习会员,无法参与月月领活动");
            return ActivityCheckResultDTO.builder().satisfy(false).errorMsg("不是见习会员,无法参与月月领活动").build();
        }

        Map<String, UserWideDTO> userMap = activityCommonUtilService.queryUserWideMapCache(Arrays.asList(uid, pid));
        UserWideDTO user = userMap.get(uid);
        UserWideDTO pUser = userMap.get(pid);

        DateTime strictStandardStartTime = DateUtil.parse(activityConfig.getStrictStandardStartTimeByUid(uid));
        long standardStartTimeStamp = strictStandardStartTime.getTime();
        ActivityCheckResultDTO checkUser = checkUser(activity.getBizId(), pid, uid, pUser, user, msg);
        if (checkUser != null) {
            return checkUser;
        }

        if (changeTime < standardStartTimeStamp) {
            //严格口径：（5.1前）
            //下级：当前等级（见习/初级/高级）且 用户类型（外部未签约/外部已签约），非特邀；
            //上级：当前等级（初级/高级/超级）且 用户类型（外部未签约&外部已签约），不区分是否特邀；
            SpecialInviteResponse specialInviteResponse = activityCommonUtilService.querySpecialInviteCache(uid);
            if (LeaderTypeEnum.SPECIAL_LEADER.getCode().equals(specialInviteResponse.getTag())) {
                log.info("下级为特邀会员,无法参与月月领活动,activityId={},userId={},msgId={}", activity.getId(), msg.getUid(),
                        msg.getIdempotent());
                return ActivityCheckResultDTO.builder().satisfy(false).errorMsg("下级为特邀会员，无法参与月月领活动").build();
            }
        } else {
            //5月1日0点起，去掉“下级不可为特邀”的限制；
            //下级：当前等级（见习/初级/高级）且 用户类型（外部未签约/外部已签约），不区分是否特邀；
            //上级：当前等级（初级/高级/超级）且 用户类型（外部未签约&外部已签约），不区分是否特邀；
            SpecialOldTttResultDTO specialOldTtt = activityCommonService.handleSpecialOldTttCache(uid, msg.getEventTime());
            if (!specialOldTtt.isSatisfy()) {
                return ActivityCheckResultDTO.builder().satisfy(false).errorMsg("老团推团未结束，无法参与月月领活动").build();
            }
        }

        return ActivityCheckResultDTO.builder().satisfy(true).build();
    }

    /**
     * 事件有效性校验
     *
     * @param activity
     * @param msg
     * @return
     */
    @Override
    public ActivityCheckResultDTO doActivityCheck(ActivityDTO activity, ActivityEventDTO msg) {
        //从事件消息中获取活动变更时间
        Long changeTime = msg.getEventTime();
        //佣金变跟超过60有效追溯期,不再触发做任务
        Long sixtyDaysBefore = LocalDate.now().minusDays(60L).atStartOfDay().toInstant(ZoneOffset.of("+8"))
                .toEpochMilli();
        if (changeTime < sixtyDaysBefore) {
            log.info("超出佣金变跟有效追溯期,changeTime={}", changeTime);
            return ActivityCheckResultDTO.builder().satisfy(false).errorMsg("超出佣金变跟有效追溯期").build();
        }
        //活动时间校验
        if (activity.getStartTime().getTime() > changeTime || changeTime > activity.getEndTime().getTime()) {
            log.info("超出活动时间范围,changeTime={},activitStartTime={},activityEndTime={}", changeTime,
                    activity.getStartTime().getTime(),
                    activity.getEndTime().getTime());
            return ActivityCheckResultDTO.builder().satisfy(false).errorMsg("超出活动时间范围").build();
        }

        return ActivityCheckResultDTO.builder().satisfy(true).build();
    }

    /**
     * 校验用户参与活动口径
     *
     * @param activityId
     * @param pUser
     * @param user
     * @param msg
     * @return
     */
    private ActivityCheckResultDTO checkUser(String activityId, String pid, String uid,
            UserWideDTO pUser, UserWideDTO user, ActivityEventDTO msg) {
        List<String> userLevels = Arrays.asList(UserLevelEnum.TRAINEE.getValue(), UserLevelEnum.MEMBER.getValue(),
                UserLevelEnum.SENIOR.getValue());
        //需求：上级去掉会员-TRAINEE，仅包含初级-MEMBER/高级-SENIOR/超级-SUPER，因为刷数会将所有产生了预估奖励金（产生了推广佣金的）的都刷为初级-MEMBER，
        // 所以不会对存量TRAINEE产生影响，只有新增的TRAINEE无法做月月领上级。
        //切换上级等级准入，依赖用户刷数。需刷完数再切换新准入规则，后续可去掉此判断直接使用新门槛
        List<String> pUserLevels = activityCommonUtilService.getUseNewPidLevel(uid) ? Arrays.asList(UserLevelEnum.MEMBER.getValue(), UserLevelEnum.SENIOR.getValue(),
                UserLevelEnum.SUPER.getValue()) : Arrays.asList(UserLevelEnum.TRAINEE.getValue(), UserLevelEnum.MEMBER.getValue(),
                UserLevelEnum.SENIOR.getValue(), UserLevelEnum.SUPER.getValue());

        if (user == null || pUser == null) {
            log.info("无法查询到用户信息,无法参与月月领活动，上级：{}-{}，下级：{}-{}", pid, JSON.toJSONString(pUser), uid,
                    JSON.toJSONString(user));
            return ActivityCheckResultDTO.builder().satisfy(false)
                    .errorMsg("无法查询到用户信息,无法参与月月领活动").build();
        }

        if (Objects.equals(user.getStatus(), UserCoreStatus.CANCELED.getStatus())
                || Objects.equals(pUser.getStatus(), UserCoreStatus.CANCELED.getStatus())) {
            log.info("用户已注销,无法参与月月领活动，上级状态：{}-{}，下级状态：{}-{}", pid,
                    Optional.ofNullable(UserCoreStatus.findByCode(pUser.getStatus())).map(UserCoreStatus::getDesc)
                            .orElse(null),
                    uid, Optional.ofNullable(UserCoreStatus.findByCode(user.getStatus())).map(UserCoreStatus::getDesc)
                            .orElse(null));
            return ActivityCheckResultDTO.builder().satisfy(false)
                    .errorMsg("用户已注销,无法参与月月领活动").build();
        }

        String levelId = user.getLevelId();
        if (!userLevels.contains(levelId)) {
            String level = Optional.ofNullable(UserLevelEnum.getByValue(levelId)).map(UserLevelEnum::getDesc)
                    .orElse(null);
            String baseMsg = String.format("下级不符合等级见习/初级/高级,无法参与月月领活动,当前等级：%s", level);
            log.info("{},activityId={},userId={},msgId={}", baseMsg, activityId, msg.getUid(), msg.getIdempotent());
            return ActivityCheckResultDTO.builder().satisfy(false).errorMsg(baseMsg).build();
        }

        if (!StaffFromTypeEnum.isOuterSign(user.getType())) {
            log.info("下级非外部用户,无法参与月月领活动,activityId={},userId={},msgId={}", activityId, msg.getUid(),
                    msg.getIdempotent());
            return ActivityCheckResultDTO.builder().satisfy(false).errorMsg("下级非外部用户，无法参与月月领活动").build();
        }

        String pLevelId = pUser.getLevelId();
        if (!pUserLevels.contains(pLevelId)) {
            String level = Optional.ofNullable(UserLevelEnum.getByValue(pLevelId)).map(UserLevelEnum::getDesc)
                    .orElse(null);
            String pUserLevelsText = pUserLevels.stream().map(i -> UserLevelEnum.getByValue(i)).filter(Objects::nonNull)
                    .map(UserLevelEnum::getDesc).collect(Collectors.joining("/"));
            String baseMsg = new StringBuilder("上级不符合等级：").append(pUserLevelsText)
                    .append(",无法参与月月领活动,当前等级：").append(level).toString();
            log.info("{},activityId={},userId={},msgId={}", baseMsg, activityId, msg.getUid(), msg.getIdempotent());
            return ActivityCheckResultDTO.builder().satisfy(false).errorMsg(baseMsg).build();
        }

        if (!StaffFromTypeEnum.isOuterSign(pUser.getType())) {
            log.info("上级非外部用户,无法参与月月领活动,activityId={},userId={},msgId={}", activityId, msg.getUid(),
                    msg.getIdempotent());
            return ActivityCheckResultDTO.builder().satisfy(false).errorMsg("上级非外部用户，无法参与月月领活动").build();
        }

        return null;
    }

    //新注册见习会员30后才能参与月月领
    private boolean checkTraineeTime(Long changeTime, Long traineeTime) {
        LocalDateTime localTraineeTime = LocalDateTime
                .ofInstant(Instant.ofEpochMilli(traineeTime), ZoneId.systemDefault());
        Long traineeTimeThirtyDaysAfter = localTraineeTime.toLocalDate().plusDays(30).atStartOfDay()
                .toInstant(ZoneOffset.of("+8"))
                .toEpochMilli();
        return changeTime >= traineeTimeThirtyDaysAfter;
    }

    //老普通TTT团长不可参与月月领
    private boolean oldTTT(String uid) {
        QuFaUserHasJoinNormalPromoteRequest request = new QuFaUserHasJoinNormalPromoteRequest();
        request.setUid(uid);
        log.info("groupTaskDependency.checkHasJoinNormalPromote ,uid={}", uid);
        QuFaUserHasJoinNormalPromoteRes res = groupTaskDependency.checkHasJoinNormalPromote(request);
        log.info("groupTaskDependency.checkHasJoinNormalPromote,res={}", res);
        return res.getHasJoin() == 1;
    }

}